using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Net;
using System.Drawing;
using System.IO;
using System.Globalization;

namespace IGGCore
{
    /// <summary>
    /// Manager of rss feeds
    /// </summary>
    public class NewsParser
    {
        public delegate void NewsParsingHandler(string update);
        public event NewsParsingHandler NewsParsingUpdated;

        private Dictionary<string, int> m_lexicon = null;

        private TextInfo myTI = new CultureInfo("en-US", false).TextInfo;
        private int dateBonus = 500;

        /// <summary>
        /// Get an importance ratio for a news text
        /// </summary>
        private int GetRatio(string analyseText)
        {
            if (m_lexicon == null)
            {
                InitializeLexicon();
            }

            int ratio = 0;
            analyseText = analyseText.ToLower();
            foreach (string key in m_lexicon.Keys)
            {
                if (analyseText.IndexOf(key) > -1)
                {
                    ratio += m_lexicon[key];
                }
            }
            return ratio;
        }

        /// <summary>
        /// Launch an event status if something is registered
        /// </summary>
        private void UpdateStatus(string eventStatus)
        {
            if (NewsParsingUpdated != null)
            {
                NewsParsingUpdated(eventStatus);
            }
        }

        /// <summary>
        /// Return news from a source
        /// </summary>
        public List<News> GetRssNews(string url, int num, bool picNeeded)
        {
            List<News> newsList = new List<News>();
            XmlDocument rssDoc = new XmlDocument();
            string contentNS = "http://purl.org/rss/1.0/modules/content/";
            UpdateStatus("Retrieving online rss news");
            try
            {
                rssDoc.Load(url);
                XmlNode nodeRss = rssDoc.SelectSingleNode("rss");
                XmlNode nodeChannel = nodeRss.SelectSingleNode("channel");
                XmlNodeList nodeItems = nodeChannel.SelectNodes("item");

                if (nodeItems != null && nodeItems.Count > 0)
                {
                    if (nodeItems.Count < num)
                    {
                        num = nodeItems.Count;
                    }
                    for (int i = 0; i < nodeItems.Count; i++)
                    {
                        News news = new News();
                        XmlNode nodeItem = nodeItems[i];
                        XmlNode descItem = nodeItem.SelectSingleNode("description");
                        XmlElement elItem = nodeItem as XmlElement;
                        news.Provider = nodeChannel.SelectSingleNode("title").InnerText;
                        news.Date = nodeItem.SelectSingleNode("pubDate").InnerText;
                        news.Title = nodeItem.SelectSingleNode("title").InnerText;
                        news.Link = nodeItem.SelectSingleNode("link").InnerText;

                        XmlNodeList elContents = elItem.GetElementsByTagName("encoded", contentNS);
                        if (elContents != null && elContents.Count > 0)
                        {
                            news.Content = elContents[0].InnerText;
                        }
                        else
                        {
                            if (descItem != null)
                            {
                                news.Content = descItem.InnerText;
                            }
                        }

                        news.Content = ToolBox.FormatWebContent(news.Content);
                        news.Content = ToolBox.RemoveTag("a", news.Content);
                        news.Content = ToolBox.RemoveTag("img", news.Content);

                        if (news.Content.Length > 3500)
                        {
                            news.Content = news.Content.Substring(0, 3500);
                        }
                        news.Title = myTI.ToTitleCase(news.Title);
                        AnalyzeNews(news, picNeeded);
                        if (news.Link.Contains("mlb.com/es") == false)
                        {
                            newsList.Add(news);
                        }
                        if (newsList.Count >= num)
                        {
                            break;
                        }
                        
                    }
                }
            }
            catch (WebException)
            {
                rssDoc = null;
            }
            return newsList;
        }

        /// <summary>
        /// Retrieve news items from mlb.com
        /// </summary>
        public void UpdateNews(Scoreboard board, bool picNeeded)
        {
            dateBonus = 500;
            List<News> resultNews = GetRssNews(CoreConstants.NEWS_URL_MLB, 15, picNeeded);
            List<News> newsList = new List<News>();
            foreach (News item in resultNews)
            {
                //AnalyzeNews(item, picNeeded);
                if (picNeeded)
                {
                    item.ImageURL = GetPictureForNews(item);
                    if (item.ImageURL == null)
                    {
                        // second try
                        item.ImageURL = GetPictureForNews(item);

                        // third try
                        if (item.ImageURL == null)
                        {
                            item.ImageURL = GetPictureForNews(item);
                        }
                    }
                }
                newsList.Add(item);
            }
            newsList.Sort();
            board.News = newsList;
        }

        /// <summary>
        /// Get a picture for a news
        /// </summary>
        private string GetPictureForNews(News news)
        {
            string response = "";
            try
            {
                if (news.Teams.Count > 0)
                {
                    string content = null;
                    StreamReader reader = null;
                    try
                    {
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(news.Teams[0].YahooPage);
                        reader = new StreamReader(request.GetResponse().GetResponseStream());
                        content = reader.ReadToEnd();

                        int index = content.IndexOf("oPhotoViewerGlobals.imageDataObj =");
                        int endindex = content.IndexOf("}};", index);
                        string gallery = content.Substring(index, endindex - index);
                        index = gallery.IndexOf("\"image1\":{");
                        List<string> imagesRawStrings = new List<string>();
                        int counter = 1;
                        while (index > -1)
                        {
                            counter++;
                            endindex = gallery.IndexOf("\"image" + counter + "\":{");
                            if (endindex > -1)
                            {
                                imagesRawStrings.Add(gallery.Substring(index, endindex - index));
                            }
                            else
                            {
                                imagesRawStrings.Add(gallery.Substring(index));
                            }
                            index = endindex;
                        }
                        string selectedRaw = null;
                        if (news.Players.Count > 0)
                        {
                            foreach (string rawIng in imagesRawStrings)
                            {
                                if (rawIng.Contains(news.Players[0]))
                                {
                                    selectedRaw = rawIng;
                                    break;
                                }
                            }
                            if (selectedRaw == null)
                            {
                                foreach (string rawIng in imagesRawStrings)
                                {
                                    for (int i = 1; i < news.Players.Count && selectedRaw == null; i++)
                                    {
                                        if (rawIng.Contains(news.Players[i]))
                                        {
                                            selectedRaw = rawIng;
                                            break;
                                        }
                                    }
                                    if (selectedRaw != null)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                        if (selectedRaw != null)
                        {
                            index = selectedRaw.IndexOf("\"image_photo_url\":");
                            endindex = selectedRaw.IndexOf(",", index);
                            string pict = selectedRaw.Substring(index, (endindex - index)-1);
                            response = pict.Substring(pict.IndexOf("http"));
                            response = response.Replace("\\/", "/");
                        }
                    }
                    catch
                    {
                        response = null;
                    }
                    finally
                    {
                        if (reader != null)
                        {
                            reader.Close();
                        }
                    }
                }
            }
            catch
            {
                response = null;
            }
            return response;
        }

        /// <summary>
        /// Check a news content/title for team and player
        /// </summary>
        /// <param name="news"></param>
        private void AnalyzeNews(News news, bool picNeeded)
        {
            news.HeadlineRatio = GetRatio(news.Title);

            if (news.Content.Trim() == string.Empty)
            {
                news.HeadlineRatio = -200;
            }
            news.HeadlineRatio += dateBonus;
            dateBonus -= 50;
            if (dateBonus < 0)
            {
                dateBonus = 0;
            }
            if (picNeeded == false)
            {
                return;
            }

            TeamIdentification identifiedTeam = null;

            // step 1 - check title for first mentioned team
            string[] titleArray = news.Title.Split(new string[] { "' ", " ", ",", ".", ";" }, StringSplitOptions.RemoveEmptyEntries);
            string[] contentArray = news.Content.Split(new string[] { "' ", " ", ",", ".", ";" }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string word in titleArray)
            {
                TeamIdentification team = TeamIdentification.GetTeam(word);
                if (team != null)
                {
                    news.Teams.Add(team);
                    break;
                }
            }

            // step 2 - check news content
            if (identifiedTeam == null)
            {
                
                foreach (string word in contentArray)
                {
                    TeamIdentification team = TeamIdentification.GetTeam(word);
                    if (team != null)
                    {
                        news.Teams.Add(team);
                        break;
                    }
                }
            }

            // PAIR OF CAPITALIZED WORDS
            if (identifiedTeam == null)
            {
                List<string> pairsList = new List<string>();
                string pair = null;
                foreach (string word in titleArray)
                {
                    if (ToolBox.IsCapitalized(word))
                    {
                        if (pair != null)
                        {
                            pairsList.Add(pair + " " + word);
                        }
                        pair = word;
                    }
                    else
                    {
                        pair = null;
                    }
                }
                pair = null;
                foreach (string word in contentArray)
                {
                    if (ToolBox.IsCapitalized(word))
                    {
                        if (pair != null)
                        {
                            pairsList.Add(pair + " " + word);
                        }
                        pair = word;
                    }
                    else
                    {
                        pair = null;
                    }
                }
                foreach (string pairword in pairsList)
                {
                    string pairwordForm = pairword;
                    if (pairword.IndexOf("'s") > -1)
                    {
                        pairwordForm = pairword.Remove(pairword.IndexOf("'s"), 2);
                    }
                    TeamIdentification team = TeamIdentification.GetTeam(pairwordForm);
                    if (team != null)
                    {
                        news.Teams.Add(team);
                        break;
                    }
                    else
                    {
                        news.Players.Add(pairwordForm);
                    }
                }
            }

            
        }

        /// <summary>
        /// Initialize the lexicon
        /// </summary>
        private void InitializeLexicon()
        {
            m_lexicon = new Dictionary<string, int>();
            m_lexicon.Add("10th", 10);
            m_lexicon.Add("11th", 12);
            m_lexicon.Add("12th", 15);
            m_lexicon.Add("13th", 16);
            m_lexicon.Add("14th", 17);
            m_lexicon.Add("15th", 20);
            m_lexicon.Add("16th", 22);
            m_lexicon.Add("17th", 23);
            m_lexicon.Add("18th", 25);
            m_lexicon.Add("academy", -5);
            m_lexicon.Add("acquire", 25);
            m_lexicon.Add("apply for", -85);
            m_lexicon.Add("at bat", -15);
            m_lexicon.Add("benches", 13);
            m_lexicon.Add("big night", 5);
            m_lexicon.Add("breaks", 20);
            m_lexicon.Add("champion", 50);
            m_lexicon.Add("confirm", 5);
            m_lexicon.Add("contusion", -5);
            m_lexicon.Add("cut", 12);
            m_lexicon.Add("day to day", 3);
            m_lexicon.Add("dinner", -15);
            m_lexicon.Add("disabled", 15);
            m_lexicon.Add("dl", 5);
            m_lexicon.Add("dream job", -85);
            m_lexicon.Add("drives", 4);
            m_lexicon.Add("duel", 5);
            m_lexicon.Add("escape", 5);
            m_lexicon.Add("extras", 10);
            m_lexicon.Add("familiar", -5);
            m_lexicon.Add("families", -15);
            m_lexicon.Add("fantasy", -85);
            m_lexicon.Add("today's mlb starting lineups", -85);
            m_lexicon.Add("feels fine", -5);
            m_lexicon.Add("first start", 5);
            m_lexicon.Add("gammons", -85);
            m_lexicon.Add("gem", 15);
            m_lexicon.Add("guilty", 15);
            m_lexicon.Add("hair", -65);
            m_lexicon.Add("hero", 20);
            m_lexicon.Add("historic", 30);
            m_lexicon.Add("history", 30);
            m_lexicon.Add("homer", 10);
            m_lexicon.Add("homers twice", 10);
            m_lexicon.Add("hr", 5);
            m_lexicon.Add("hungry", -15);
            m_lexicon.Add("imminent", 5);
            m_lexicon.Add("impress", 2);
            m_lexicon.Add("injury", 10);
            m_lexicon.Add("knee", 5);
            m_lexicon.Add("late homer", 10);
            m_lexicon.Add("managerial", -5);
            m_lexicon.Add("miss start", 5);
            m_lexicon.Add("mlb.com", -1455);
            m_lexicon.Add("mlb.tv", -1455);
            m_lexicon.Add("name", 15);
            m_lexicon.Add("ninth", 9);
            m_lexicon.Add("network", -85);
            m_lexicon.Add("no-hit", 100);
            m_lexicon.Add("officially", 5);
            m_lexicon.Add("out of action", 10);
            m_lexicon.Add("out until", 12);
            m_lexicon.Add("pennant", 50);
            m_lexicon.Add("perfect", 30);
            m_lexicon.Add("perfect fit", -30);
            m_lexicon.Add("perfect managerial", -30);
            m_lexicon.Add("perfect game", 500);
            m_lexicon.Add("preview", -35);
            m_lexicon.Add("pro debut", 45);
            m_lexicon.Add("promotes", -85);
            m_lexicon.Add("quiets", 10);
            m_lexicon.Add("rally", 15);
            m_lexicon.Add("ready", 5);
            m_lexicon.Add("reflects", -5);
            m_lexicon.Add("relaxed", -10);
            m_lexicon.Add("release", 20);
            m_lexicon.Add("role", -10);
            m_lexicon.Add("rosters", -15);
            m_lexicon.Add("rotation", 10);
            m_lexicon.Add("salaries", -85);
            m_lexicon.Add("scare", 3);
            m_lexicon.Add("second opinion", 10);
            m_lexicon.Add("seek", 10);
            m_lexicon.Add("series victory", 15);
            m_lexicon.Add("sharp", 8);
            m_lexicon.Add("shut down", 12);
            m_lexicon.Add("significant", 25);
            m_lexicon.Add("simulated", -15);
            m_lexicon.Add("sluggish", -5);
            m_lexicon.Add("sore neck", 5);
            m_lexicon.Add("spark", 3);
            m_lexicon.Add("spring", -5);
            m_lexicon.Add("streak", 15);
            m_lexicon.Add("surge", 5);
            m_lexicon.Add("surgery", 10);
            m_lexicon.Add("three homers", 15);
            m_lexicon.Add("title", 50);
            m_lexicon.Add("tommy john", 25);
            m_lexicon.Add("tuneup", -15);
            m_lexicon.Add("trade", 25);
            m_lexicon.Add("out indefinitely", 15);
            m_lexicon.Add("victory", 5);
            m_lexicon.Add("vote now", -85);
            m_lexicon.Add("yes", -45);
            m_lexicon.Add("walk off", 25);
            m_lexicon.Add("walk-off", 25);
            m_lexicon.Add("wild", 5);
            m_lexicon.Add("wire", 5);
        }
    }
}
